import crypto from 'crypto';
import axios, { AxiosRequestConfig, AxiosResponse, isAxiosError } from 'axios';

/**
 * 青牛云API配置接口
 */
export interface QnyConfig {
    baseUrl: string;
    monitorCenterId: string;
    fireUnitId: string;
    token: string;
    ticket: string;
}

/**
 * 请求参数接口
 */
export interface RequestOptions {
    method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
    headers?: Record<string, string>;
    body?: any;
    params?: Record<string, any>;
}

/**
 * 签名算法
 * 报文内容（可为空字符串）、时间戳、签名票据都采用 utf-8 编码，
 * 报文内容+时间戳+签名票据拼接成字符串，对其作 sha1 加密得到签名。
 * 
 * @param message 报文内容（可为空字符串）
 * @param timestamp 时间戳
 * @param ticket 签名票据
 * @returns 签名结果（16进制字符串）
 */
export const qnySignature = (message: string, timestamp: string, ticket: string) => {
    try {
        // 步骤1和2：按顺序拼接报文内容、时间戳、签名票据
        const string1 = message + timestamp + ticket;

        // 步骤3：对 string1 进行 sha1 签名
        const hash = crypto.createHash('sha1'); // 使用sha1算法
        hash.update(string1, 'utf8');  // 使用UTF-8编码
        // 获取十六进制格式的哈希值
        const signature = hash.digest('hex');
        return signature;
    } catch (error) {
        console.error('生成签名失败:', error);
        return "";
    }
};

/**
 * 青牛云API请求管理类（单例模式）
 */
export class QnyHttpClient {
    // 单例实例
    private static instance: QnyHttpClient | null = null;

    // 配置信息
    private config: QnyConfig = {
        baseUrl: "",
        monitorCenterId: "",
        fireUnitId: "",
        token: "",
        ticket: "",
    };

    /**
     * 私有构造函数，防止外部直接创建实例
     */
    private constructor() {
        this.loadEnvironmentConfig();
        this.initConfig();
    }

    /**
     * 从环境变量加载配置
     */
    private loadEnvironmentConfig(): void {
        // 尝试从不同环境变量名称中获取配置
        this.config.baseUrl = process.env.QNY_BASE_URL || "";
        this.config.monitorCenterId = process.env.QNY_MONITOR_CENTER_ID || "";
        this.config.fireUnitId = process.env.QNY_FIRE_UNIT_ID || "";
        this.config.ticket = process.env.QNY_FIRE_TICKET || "";
    }

    private async initConfig() {
        this.config.token = ""; // 根据API文档设置适当的初始值
        try {
            // 获取token
            await this.getToken<any>();
        } catch (error) {
            this.handleError("获取Token失败", error);
        }
    }

    /**
     * 处理API错误
     */
    private handleError(message: string, error: any): void {
        console.error(`${message}:`, error.message);
    }

    /**
     * 获取QnyHttpClient实例（单例）
     * @param config 配置信息（可选）
     * @returns QnyHttpClient实例
     */
    public static getInstance(config?: QnyConfig): QnyHttpClient {

        // 如果实例不存在，创建新实例
        if (!QnyHttpClient.instance) {
            QnyHttpClient.instance = new QnyHttpClient();
        }
        // 如果提供了新的配置，更新已有实例的配置
        else if (config) {
            QnyHttpClient.instance.updateConfig(config);
        }

        return QnyHttpClient.instance;
    }

    /**
     * 更新配置信息
     * @param config 新的配置信息
     */
    public updateConfig(config: Partial<QnyConfig>): void {
        this.config = { ...this.config, ...config };
    }

    /**
     * 设置token
     * @param token 新的token
     */
    public setToken(token: string): void {
        this.config.token = token;
    }

    /**
     * 手动刷新token
     */
    public async refreshToken(): Promise<boolean> {
        try {
            const tokenResponse = await this.getToken<any>();
            if (tokenResponse && (tokenResponse.token || tokenResponse.data?.token)) {
                this.config.token = tokenResponse.token || tokenResponse.data?.token || "";
                console.log("Token刷新成功");
                return true;
            }
            return false;
        } catch (error) {
            console.error("刷新Token失败", error);
            return false;
        }
    }

    /**
     * 生成请求头
     * @param message 消息内容
     * @returns 包含认证信息的请求头
     */
    private generateHeaders(message: string = ""): Record<string, string> {
        const timestamp = new Date().getTime().toString();
        const sig = qnySignature(message, timestamp, this.config.ticket);
        return {
            "Monitor-Center-Id": this.config.monitorCenterId,
            "Fire-Unit-Id": this.config.fireUnitId,
            "X-Timestamp": timestamp,
            "X-Signature": sig,
            "Content-Type": "application/json",
            "token": this.config.token,
            "contenttype": "application/json"
        };
    }

    /**
     * 构建URL（处理查询参数）
     * @param endpoint API端点
     * @param params 查询参数
     * @returns 完整URL
     */
    private buildUrl(endpoint: string): string {
        return `${this.config.baseUrl}${endpoint}`;
    }

    /**
     * 发送请求
     * @param endpoint API端点
     * @param options 请求选项
     * @returns 响应数据
     */
    async request<T>(endpoint: string, options: RequestOptions = {}): Promise<T> {
        try {
            const { method = 'GET', body, params, headers = {} } = options;
            // 构建 axios 请求配置
            const axiosConfig: AxiosRequestConfig = {
                method: method,
                url: this.buildUrl(endpoint),
                headers: {
                    ...headers,
                    ...this.generateHeaders()
                },
                params: params,
                data: body,
                // 添加超时设置
                timeout: 30000, // 30秒超时
                // 添加重试配置
                maxRedirects: 5
            };
            console.log("token",this.config.token)
            const response: AxiosResponse = await axios(axiosConfig);
            if (response.status === 200) {
                if (response.data.code === 1) {
                    return response.data;
                } else {
                    throw new Error(response.data.message);
                }
            }
            throw new Error(response.data.message);
        } catch (error: any) {
            // 如果是授权问题，尝试刷新token并重试
            if (isAxiosError(error) && error.response?.status === 401) {
                console.log("检测到401错误，尝试刷新token并重试请求");
                const refreshed = await this.refreshToken();
                if (refreshed) {
                    console.log("Token已刷新，重试请求");
                    return this.request<T>(endpoint, options);
                }
            }
            return {
                code: 500,
                message: "请求失败"
            } as T;
        }
    }

    /**
     * GET请求
     * @param endpoint API端点
     * @param params 查询参数
     * @param options 其他请求选项
     * @returns 响应数据
     */
    async get<T>(endpoint: string, params?: Record<string, any>, options: Omit<RequestOptions, 'method' | 'params'> = {}): Promise<T> {
        return this.request<T>(endpoint, {
            ...options,
            method: 'GET',
            params
        });
    }

    /**
     * POST请求
     * @param endpoint API端点
     * @param body 请求体
     * @param options 其他请求选项
     * @returns 响应数据
     */
    async post<T>(endpoint: string, body?: any, options: Omit<RequestOptions, 'method' | 'body'> = {}): Promise<T> {
        return this.request<T>(endpoint, {
            ...options,
            method: 'POST',
            body
        });
    }

    /**
     * PUT请求
     * @param endpoint API端点
     * @param body 请求体
     * @param options 其他请求选项
     * @returns 响应数据
     */
    async put<T>(endpoint: string, body?: any, options: Omit<RequestOptions, 'method' | 'body'> = {}): Promise<T> {
        return this.request<T>(endpoint, {
            ...options,
            method: 'PUT',
            body
        });
    }

    /**
     * DELETE请求
     * @param endpoint API端点
     * @param params 查询参数
     * @param options 其他请求选项
     * @returns 响应数据
     */
    async delete<T>(endpoint: string, params?: Record<string, any>, options: Omit<RequestOptions, 'method' | 'params'> = {}): Promise<T> {
        return this.request<T>(endpoint, {
            ...options,
            method: 'DELETE',
            params
        });
    }

    /**
     * 获取token
     * @returns token响应
     */
    private async getToken<T>(): Promise<T> {
        try {
            const res = await this.get<any>('/api/token');
            this.config.token = res.data.token;
            return res;
        } catch (error) {
            console.error("获取token失败", error);
            return { token: "" } as unknown as T;
        }
    }

    /**
     * 获取防火单元列表
     * @param params 分页参数
     * @returns 防火单元列表
     */
    async getFireUnitList<T>(params: {
        pageSize: number;
        pageNum: number;
        date: string;
    }): Promise<T> {
        return this.get<T>('/api/fireUnit/list', params);
    }

    /**
     * 查询设施列表
     * @param params 分页参数
     * @returns 设施列表
     */
    async getFacilitiesList<T>(params: any): Promise<T> {
        return this.get<T>('/api/facilities/list', {
            ...params
        });
    }
     /**
     * 查询设施详情
     */
    async getFacilitiesInfo<T>(params: any): Promise<T> {
        return this.get<T>('/api/facilities', {
            ...params
        });
    }
    /**
     * 查询设施警情记录
     */
    async getFacilitiesAlarmList<T>(params: any): Promise<T> {
        return this.get<T>('/api/alarm/list', {
            ...params
        });
    }

    /**
     * 查询场所列表
     */
    async getPlaceList<T>(params: any): Promise<T> {
        return this.get<T>('/api/place/list', {
            ...params
        });
    }
    /**
     * 查询联系人列表
     */
    async getLinkmanList<T>(params: any): Promise<T> {
        return this.get<T>('/api/linkman/list', {
            ...params
        });
    }
    /**
     * 查询报送记录
     */
    async getPushLogList<T>(params: any): Promise<T> {
        return this.get<T>('/api/pushLog', {
            ...params
        });
    }
    /**
     * 查询短信记录
     */
    async getSmsLogList<T>(params: any): Promise<T> {
        return this.get<T>('/api/smsLog/list', {
            ...params
        });
    }

    /**
     * 查询语音记录
     */
    async getVmsLogList<T>(params: any): Promise<T> {
        return this.get<T>('/api/vmsLog/list', {
            ...params
        });
    }

    /**
     * 查询操作日志（设施）
     */
    async getFacilitiesLogList<T>(params: any): Promise<T> {
        return this.get<T>('/api/log/deviceList', {
            ...params
        });
    }

    /**
     * 查询操作日志（社会单位）
     */
    async getFireUnitLogList<T>(params: any): Promise<T> {
        return this.get<T>('/api/log/fireUnitList', {
            ...params
        });
    }

    /**
     * 查询操作日志（场所）
     */
    async getPlaceLogList<T>(params: any): Promise<T> {
        return this.get<T>('/api/log/placeList', {
            ...params
        });
    }


    /**
     * 字典-警情事件类型
     */
    async getStatType<T>(): Promise<T> {
        return this.get<T>('/api/dict/statType');
    }

    /**
     * 字典-警情事件
     */
    async getStatEvent<T>(params: any): Promise<T> {
        return this.get<T>('/api/dict/stat')
    }

    /**
     * 字典-设施类型
     */
    async getFacilities<T>(): Promise<T> {
        return this.get<T>('/api/dict/facilities');
    }
    /**
     * 字典-设施类型
     */
    async getFacilitiesType<T>(): Promise<T> {
        return this.get<T>('/api/dict/facilitesType');
    }

    /**
     * 字典-模拟量类型
     */
    async getAnalogType<T>(): Promise<T> {
        return this.get<T>('/api/dict/analogType');
    }

    /**
     * 字典-传感器类型
     */
    async getSensorType<T>(): Promise<T> {
        return this.get<T>('/api/dict/sensorType');
    }

    /**
     * 字典-语音拨打状态
     */
    async getVmsStatus<T>(): Promise<T> {
        return this.get<T>('/api/dict/vmsStatus');
    }

    /**
     * 字典-处警类型
     */
    async getTreatType<T>(): Promise<T> {
        return this.get<T>('/api/dict/treatType');
    }

    /**
     * 字典-系统类型
     */
    async getSysType<T>(): Promise<T> {
        return this.get<T>('/api/dict/sysType');
    }



}